home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / textrpg / pinfocom.002 / pinfocom / pinfocom-3.0 / file.c < prev    next >
C/C++ Source or Header  |  1992-10-21  |  13KB  |  494 lines

  1. /* file.c
  2.  *
  3.  *  ``pinfocom'' -- a portable Infocom Inc. data file interpreter.
  4.  *  Copyright (C) 1987-1992  InfoTaskForce
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; see the file COPYING.  If not, write to the
  18.  *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. /*
  22.  * $Header: RCS/file.c,v 3.0 1992/10/21 16:56:19 pds Stab $
  23.  */
  24.  
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <ctype.h>
  28. #include <errno.h>
  29.  
  30. #include "infocom.h"
  31.  
  32. #ifdef NEED_ERRNO
  33. extern int errno;
  34. #endif
  35.  
  36. static const char *fname_lst[] = {FNAME_LST,0};
  37. static const char *fext_lst[] = {"",FEXT_LST,0};
  38.  
  39. static FILE *game_file;
  40. static char gname[MAXPATHLEN + 1];
  41.  
  42. char sname[MAXPATHLEN + 1];
  43.  
  44. #ifdef SCRIPT_FILE
  45. char script_fn[MAXPATHLEN+1] = SCRIPT_FILE;
  46. #else
  47. char script_fn[MAXPATHLEN+1];
  48. #endif
  49.  
  50.  
  51. void
  52. f_error A3(int, erno, const char *, err, const char *, arg1)
  53. {
  54.     char buf[256];
  55.     char *bp;
  56.  
  57.     sprintf(buf, err, arg1);
  58.     bp = buf + strlen(buf);
  59.  
  60.     if (erno)
  61.     {
  62. #ifndef NO_STRERROR
  63.         extern char *strerror P((int));
  64.         char *cp = strerror(erno);
  65.  
  66.         sprintf(bp, ": %o: %s", erno, cp == NULL ? "<unknown>" : cp);
  67. #else
  68.         sprintf(bp, ": %o", erno);
  69. #endif
  70.     }
  71.  
  72.     if (gflags.game_state == NOT_INIT)
  73.     {
  74.         fputs(buf, stderr);
  75.         putc('\n', stderr);
  76.         putc('\n', stderr);
  77.     }
  78.     else
  79.     {
  80.         scr_putmesg(buf, 1);
  81.     }
  82. }
  83.  
  84. static void
  85. assign A2(header_t*, head, const header_t*, buffer)
  86. {
  87.     const byte  *ptr;
  88.     int         i;
  89.  
  90.     /*
  91.      * Process the raw header data in "buffer" and put
  92.      * it into the appropriate fields in "head". This
  93.      * processing is required because of the way different
  94.      * machines internally represent 'words'.
  95.      */
  96.     ptr = (const byte *)buffer;
  97.  
  98.     head->z_version       = Z_TO_BYTE_I(ptr);
  99.     head->flags_1         = Z_TO_BYTE_I(ptr);
  100.     head->release         = Z_TO_WORD_I(ptr);
  101.     head->resident_bytes  = Z_TO_WORD_I(ptr);
  102.     head->game_o          = Z_TO_WORD_I(ptr);
  103.     head->vocab_o         = Z_TO_WORD_I(ptr);
  104.     head->object_o        = Z_TO_WORD_I(ptr);
  105.     head->variable_o      = Z_TO_WORD_I(ptr);
  106.     head->save_bytes      = Z_TO_WORD_I(ptr);
  107.     head->flags_2         = Z_TO_WORD_I(ptr);
  108.     for (i = 0; i < 6; ++i)
  109.         head->serial_no[i] = Z_TO_BYTE_I(ptr);
  110.     head->common_word_o   = Z_TO_WORD_I(ptr);
  111.     head->verify_length   = Z_TO_WORD_I(ptr);
  112.     head->verify_checksum = Z_TO_WORD_I(ptr);
  113.     for (i = 0; i < 8; ++i)
  114.         head->padding1[i] = Z_TO_WORD_I(ptr);
  115.     head->fkey_o          = Z_TO_WORD_I(ptr);
  116.     for (i = 0; i < 2; ++i)
  117.         head->padding2[i] = Z_TO_WORD_I(ptr);
  118.     head->alphabet_o      = Z_TO_WORD_I(ptr);
  119.     for (i = 0; i < 5; ++i)
  120.         head->padding3[i] = Z_TO_WORD_I(ptr);
  121. }
  122.  
  123. /*
  124.  * Function:    read_header()
  125.  *
  126.  * Description:
  127.  *      This function reads in the game data file's header info.  We
  128.  *      only do this between scr_setup() and scr_begin(), so just use
  129.  *      normal printf()'s if we find an error, and just exit if we
  130.  *      can't continue.
  131.  *
  132.  * Notes:
  133.  *      This routine does not read the data-file header directly into
  134.  *      a header structure because certain machines like the VAX
  135.  *      11/780 store integers in a different way to machines based on
  136.  *      processors like the 68000 (a 68000 stores the high byte first,
  137.  *      while a VAX stores the low byte first).  Consequently, if the
  138.  *      header is read directly into a structure, the integer values
  139.  *      are interpreted differently by the two machines.
  140.  */
  141. void
  142. read_header A1(header_t*, head)
  143. {
  144.     extern void exit P((int));
  145.     header_t  buffer;
  146.  
  147.     if (fseek(game_file, 0L, 0) < 0)
  148.     {
  149.         f_error(errno, "Failed to seek to beginning of file `%s'", gname);
  150.         exit(1);
  151.     }
  152.  
  153.     if (fread(&buffer, sizeof(header_t), 1, game_file) != 1)
  154.     {
  155.         f_error(errno, "Failed to read header of `%s'", gname);
  156.         exit(1);
  157.     }
  158.  
  159.     assign(head, &buffer);
  160.  
  161.     if (head->flags_1 & 0x01)
  162.     {
  163.         f_error(0, "Invalid header in file `%s'", gname);
  164.         exit(1);
  165.     }
  166. }
  167.  
  168. /*
  169.  * Open a file for reading; if the parameter is NULL then look through
  170.  * the name,extension list pairs to try to find one there.  Return a
  171.  * pointer to it, whatever it is.
  172.  */
  173. const char *
  174. open_file A1(const char*, filename)
  175. {
  176.     const char *fn = gname;
  177.     char *endp = gname;
  178.  
  179.     if (filename != NULL)
  180.     {
  181.         const char **exp;
  182.  
  183.         strcpy(gname, filename);
  184.         endp = &gname[strlen(gname)];
  185.  
  186.         if ((game_file = fopen(gname, "rb")) != NULL)
  187.         {
  188.             int len;
  189.  
  190.             for (exp=fext_lst; *exp != NULL; ++exp)
  191.             {
  192.                 if (((len = strlen(*exp)) != 0) && !strcmp(endp - len, *exp))
  193.                     break;
  194.             }
  195.  
  196.             if (*exp != NULL)
  197.                 endp -= len;
  198.  
  199.             goto done;
  200.         }
  201.  
  202.         for (exp = fext_lst; *exp != NULL; ++exp)
  203.         {
  204.             strcpy(endp, *exp);
  205.             if ((game_file = fopen(gname, "rb")) != NULL)
  206.                 goto done;
  207.         }
  208.  
  209.         f_error(errno, "Cannot open file `%s'", filename);
  210.         fn = NULL;
  211.     }
  212.     else
  213.     {
  214.         const char **nmp;
  215.  
  216.         for (nmp = fname_lst; *nmp != NULL; ++nmp)
  217.         {
  218.             const char **exp;
  219.  
  220.             strcpy(gname, *nmp);
  221.             endp = &gname[strlen(gname)];
  222.  
  223.             for (exp = fext_lst; *exp != NULL; ++exp)
  224.             {
  225.                 strcpy(endp, *exp);
  226.                 if ((game_file = fopen(gname, "rb")) != NULL)
  227.                     goto done;
  228.             }
  229.         }
  230.  
  231.         f_error(0, "Could not find a game to play!", NULL);
  232.         fn = NULL;
  233.     }
  234.  
  235.  done:
  236.     *endp = '\0';
  237.  
  238.     strcpy(sname, gname);
  239. #ifdef SAVE_EXT
  240.     strcat(sname, SAVE_EXT);
  241. #endif
  242. #ifdef SCRIPT_EXT
  243.     sprintf(script_fn, "%s%s", gname, SCRIPT_EXT);
  244. #endif
  245.  
  246.     return (fn);
  247. }
  248.  
  249. void
  250. close_file()
  251. {
  252.     if (fclose(game_file))
  253.         scr_putline("Cannot Close Game File");
  254. }
  255.  
  256. void
  257. load_page A3(word, block, word, num_blocks, byte*, ptr)
  258. {
  259.     extern file_t   file_info;
  260.  
  261.     long found;
  262.     long offset;
  263.     long num_bytes;
  264.  
  265.     /*
  266.      * Read "num_block" blocks from Game File, starting with block
  267.      * "block", into the location pointed to by "ptr".
  268.      */
  269.     offset = (long)block * BLOCK_SIZE;
  270.     num_bytes = (long)num_blocks * BLOCK_SIZE;
  271.  
  272.     if (fseek(game_file, offset, 0) < 0)
  273.     {
  274.         f_error(errno, "Failed to seek to required offset in `%s'", gname);
  275.         quit();
  276.     }
  277.     else if ((found = fread(ptr, 1, num_bytes, game_file)) < num_bytes)
  278.     {
  279.         /*
  280.          * Check if this is the last block: some games (notably
  281.          * MS-DOS) don't have the full last block on the disk.  If
  282.          * this isn't the last block, print an error.  Otherwise, zero
  283.          * out the rest of the page.
  284.          */
  285.         if ((found / BLOCK_SIZE != num_blocks - 1)
  286.             || (block + num_blocks - 1 != file_info.pages))
  287.         {
  288.             f_error(errno, "Failed to load required blocks in `%s'", gname);
  289.             quit();
  290.         }
  291.  
  292.         for (ptr += found; found < num_bytes; ++found, ++ptr)
  293.             *ptr = '\0';
  294.     }
  295. }
  296.  
  297. void
  298. save()
  299. {
  300.     extern byte     *base_ptr;
  301.     extern word     save_blocks;
  302.     extern byte     *end_res_p;
  303.     extern word     *stack;
  304.     extern word     *stack_base;
  305.     extern word     *stack_var_ptr;
  306.     extern word     pc_page;
  307.     extern word     pc_offset;
  308.  
  309.     FILE    *fp;
  310.     int     ret = 0;
  311.  
  312.     /*
  313.      * We save the the program counter, the stack offset, the
  314.      * stack_var offset, the stack itself, and finally the resident
  315.      * impure storage.  This overwrites the lowest 8 bytes of the
  316.      * stack; hopefully those aren't being used...
  317.      */
  318.     if ((fp = scr_open_sf(MAXPATHLEN+1, (char *)sname, SF_SAVE)) == NULL)
  319.     {
  320.         if (errno != 0)
  321.             f_error(errno, "Cannot open save file `%s'", sname);
  322.     }
  323.     else
  324.     {
  325.         word *sp;
  326.  
  327.         sp = (word *)end_res_p;
  328.         *(sp++) = pc_page;
  329.         *(sp++) = pc_offset;
  330.         *(sp++) = stack_base - stack;
  331.         *sp     = stack_base - stack_var_ptr;
  332.  
  333.         if ((fwrite(end_res_p, sizeof(byte), STACK_SIZE, fp) != STACK_SIZE)
  334.             || (fwrite(base_ptr, BLOCK_SIZE, save_blocks, fp) != save_blocks))
  335.         {
  336.             f_error(errno, "Cannot write save file `%s'", sname);
  337.             fclose(fp);
  338.         }
  339.         else
  340.         {
  341.             scr_close_sf(sname, fp, SF_SAVE);
  342.             ret = 1;
  343.         }
  344.     }
  345.  
  346.     ret_value(ret);
  347. }
  348.  
  349. /*
  350.  * Check to see if a restored game is the same as our current game:
  351.  * note that everything except the serial number, verify length, and
  352.  * verify checksum must be identical.  If they are copy over the new
  353.  * verify length and checksum so $verify will still work...
  354.  */
  355. static Bool
  356. check A1(header_t*, info)
  357. {
  358. #define CMP(_1,_2,_f)   ((_1)->_f == (_2)->_f)
  359.  
  360.     extern header_t   data_head;
  361.  
  362.     Bool good = 0;
  363.  
  364.     if (CMP(info, &data_head, z_version)
  365.         && CMP(info, &data_head, release)
  366.         && CMP(info, &data_head, resident_bytes)
  367.         && CMP(info, &data_head, game_o)
  368.         && CMP(info, &data_head, vocab_o)
  369.         && CMP(info, &data_head, object_o)
  370.         && CMP(info, &data_head, variable_o)
  371.         && CMP(info, &data_head, save_bytes)
  372.         && CMP(info, &data_head, common_word_o)
  373.         && CMP(info, &data_head, fkey_o)
  374.         && CMP(info, &data_head, alphabet_o))
  375.     {
  376.         data_head.flags_1 = info->flags_1;
  377.         data_head.verify_length = info->verify_length;
  378.         data_head.verify_checksum = info->verify_checksum;
  379.  
  380.         good = 1;
  381.     }
  382.  
  383.     return (good);
  384. }
  385.  
  386. void
  387. restore()
  388. {
  389.     extern byte     *base_ptr;
  390.     extern word     save_blocks;
  391.     extern byte     *end_res_p;
  392.     extern word     *stack;
  393.     extern word     *stack_base;
  394.     extern word     *stack_var_ptr;
  395.     extern word     pc_page;
  396.     extern word     pc_offset;
  397.  
  398.     FILE    *fp;
  399.     int     ret = 0;
  400.     int     len = MAXPATHLEN+1;
  401.  
  402.     errno = 0;
  403.  
  404.     /*
  405.      * If we're restoring a game specified on the command line, print
  406.      * a message about it...
  407.      */
  408.     if (gflags.game_state != PLAY_GAME)
  409.     {
  410.         char buf[MAXPATHLEN+30];
  411.  
  412.         sprintf(buf, "Restoring saved game `%s' ...", sname);
  413.         if (gflags.game_state == NOT_INIT)
  414.             puts(buf);
  415.         else
  416.             scr_putline(buf);
  417.         len = 0;
  418.     }
  419.  
  420.     /*
  421.      * Ask the user for a saved game filename to restore and open it;
  422.      * if that fails then print an error.
  423.      */
  424.     if ((fp = scr_open_sf(len, (char *)sname, SF_RESTORE)) == NULL)
  425.     {
  426.         if (errno != 0)
  427.             f_error(errno, "Opening saved file ", sname);
  428.         ret = -1 + (gflags.game_state == INIT_GAME);
  429.     }
  430.     /*
  431.      * From here on we're destroying the current game data, so if the
  432.      * restore fails here we have no choice but to restart the game
  433.      * from scratch.  Keep the scripting bit set correctly tho...
  434.      */
  435.     else
  436.     {
  437.         Bool ok;
  438.         Bool scripting;
  439.  
  440.         scripting = F2_IS_SET(B_SCRIPTING);
  441.  
  442.         ok = ((fread(end_res_p, sizeof(byte), STACK_SIZE, fp)==STACK_SIZE)
  443.               && (fread(base_ptr, BLOCK_SIZE, save_blocks, fp)==save_blocks));
  444.  
  445.         if (scripting)
  446.             F2_SETB(B_SCRIPTING);
  447.         else
  448.             F2_RESETB(B_SCRIPTING);
  449.  
  450.         if (!ok)
  451.             f_error(errno, "Error reading saved game file `%s'", sname);
  452.         else
  453.         {
  454.             header_t    test;
  455.  
  456.             assign(&test, (header_t *)base_ptr);
  457.             if (!check(&test))
  458.                 f_error(0, "Invalid saved game file `%s'", sname);
  459.             else
  460.             {
  461.                 word        *sp;
  462.  
  463.                 sp = (word *)end_res_p;
  464.                 pc_page         = *(sp++);
  465.                 pc_offset       = *(sp++);
  466.                 stack           = stack_base - *(sp++);
  467.                 stack_var_ptr   = stack_base - *sp;
  468.                 fix_pc();
  469.                 ret = 1;
  470.             }
  471.         }
  472.  
  473.         if (ret == 1)
  474.             scr_close_sf(sname, fp, SF_RESTORE);
  475.         else
  476.             fclose(fp);
  477.     }
  478.  
  479.     if (gflags.game_state != NOT_INIT)
  480.     {
  481.         if (!ret)
  482.         {
  483.             strcpy(sname, gflags.filenm);
  484. #ifdef SAVE_EXT
  485.             strcat(sname, SAVE_EXT);
  486. #endif
  487.             scr_putline("Restarting...");
  488.             restart();
  489.         }
  490.         else
  491.             ret_value(ret > 0);
  492.     }
  493. }
  494.